package server

import (
    "bytes"
    "cing.io/cing-api/core"
    singerapi "cing.io/cing-api/singer"
    singer "cing.io/cing-singer/internal"
    "cing.io/cing-singer/internal/config"
    "context"
    "fmt"
    log "github.com/sirupsen/logrus"
    "google.golang.org/grpc"
    "google.golang.org/protobuf/encoding/protojson"
    "google.golang.org/protobuf/types/known/timestamppb"
    "net"
    "net/http"
)

type singServer struct {
    singerapi.UnimplementedCingSingerServer
}

func (receiver *singServer) Singing(_ context.Context, req *singerapi.SingingCommandRequest) (*singerapi.SingingCommandResponse, error) {
    log.Debug("Command Received!")
    fun := singer.GetTaskFunc(req.TaskFullName)
    if fun == nil {
        return &singerapi.SingingCommandResponse{
            ExecuteStatus: singerapi.SingingCommandResponse_REJECT,
        }, nil
    }

    go doTaskAndResponse(req, fun)

    return &singerapi.SingingCommandResponse{
        ExecuteStatus: singerapi.SingingCommandResponse_OK,
    }, nil
}

func doTaskAndResponse(req *singerapi.SingingCommandRequest, fun func() error) {
    actualStartTime := timestamppb.Now()
    err := fun()
    actualEndTime := timestamppb.Now()

    var successful bool
    if err != nil {
        successful = false
        log.Error("task execute error: ", err)
    } else {
        successful = true
    }

    var cli http.Client

    feedback := &core.Feedback{
        TaskFullName:    req.TaskFullName,
        StartTime:       req.StartTime,
        SingerIp:        req.SingerIp,
        Successful:      successful,
        ActualStartTime: actualStartTime,
        ActualEndTime:   actualEndTime,
        Feedback:        nil,
    }

    bs, err := protojson.Marshal(feedback)
    body := bytes.NewReader(bs)

    resp, err := cli.Post(config.FeedbackUrl, config.JsonContentType, body)
    if err != nil {
        log.Error("feed back error: ", err)
    } else if resp.StatusCode == http.StatusOK {
        log.Debug("feedback success!")
    }
}

func Init(ctx context.Context) {
    var lc net.ListenConfig
    listen, err := lc.Listen(ctx, "tcp", fmt.Sprintf("%s:%d", config.Localhost, config.SingerPort))
    if err != nil {
        log.Fatal("net listening error: ", err)
    }

    server := grpc.NewServer()
    singerapi.RegisterCingSingerServer(server, &singServer{})
    log.Info("server is listening: ", listen.Addr())

    if err := server.Serve(listen); err != nil {
        log.Fatal("failed to serve: ", err)
    }
}
